I know this post is a little old but I don't see any other complete answers so here goes.
In reading the original question, I could see how you might want to implement this as separate dialogs that get launched from a main dialog, in which case you'd want to created separate ComponentDialogs that implement their own WaterfallDialog to solve the problem.
But, if you're asking if you can have multiple WaterfallDialogs within a single ComponentDialog, yes you certainly can. In order to do this, you must assign each WaterfallDialog an Id property value, by doing something like this:
var flow1steps= new WaterfallStep[] { step1, step2, step3 };
var flow2steps = new WaterfallStep[] { step1, step2, step3 };
var flow1Dialog= new WaterfallDialog(nameof(WaterfallDialog), flow1steps) { Id = "flow1" };
var flow2Dialog = new WaterfallDialog(nameof(WaterfallDialog), flow2steps) { Id = "flow2" };
In this scenario, if you wanted to start with "flow1Dialog" you would set the InitialDialogId in your constructor to "flow1Dialog" like this:
InitialDialogId = "flow1Dialog";
Then, when you're ready to redirect the dialog to "flow2", you can use flow2Dialog's WaterfallDialog.Id. For example, to redirect to flow2Dialog from any other step in your root dialog or flow1Dialog, do this:
return await stepContext.BeginDialogAsync("flow2");
BeingDialogAsync() vs ReplaceDialogAsync()
You could use BeginDialogAsync(), but unless you need control to eventually return to the originating dialog, that may result in dialog stack clutter that you don't want. Using ReplaceDialogAsync() replaces the current dialog on the stack with the new one, this can make it easier to manage looping and redirecting since the stack is not cluttered with old dialogs that you don't want to have to deal with at some point.