Having a ModulePass to schedule other Function/ModulePasses

I’d like to have an initialization and finalization step for a bunch of custom out-of-tree Function/ModulePasses. I was thinking of having a single ModulePass (call it Scheduler) that would take care of that:

// Pseudocode
struct Scheduler: ModulePass {
  runOnModule(Module module) {
    if (!is_relevant(module)) {
      // Skip non-relevant modules
      return true;
    }

    function_pass_1 = create_function_pass_1()
    function_pass_1.doInitialization(module);
    for (auto func: module.getFunctionList()) {
      function_pass_1.runOnFunction(func);
    }

    function_pass_2 = create_function_pass_2()
    function_pass_2.doInitialization(module);
    for (auto func: module.getFunctionList()) {
      function_pass_2.runOnFunction(func);
    }

    function_pass_3 = create_function_pass_3()
    function_pass_3.doInitialization(module);
    for (auto func: module.getFunctionList()) {
      function_pass_3.runOnFunction(func);
    }

    Error err = run_diagnostics(module);
    if (err) {
      // Something bad happened
      return false;
    }
  }
}

As you can see, some initialization and finalization relevant to specific passes is relevant here.
My question is: did LLVM solve this problem already (maybe using PassDependencies? Do they work for out-of-tree passes?)? Are there any clear drawbacks to using this approach?

Many thanks!