Concerns (in the broad sense, not ActiveSupport::Concern) can be separated any number of ways. The important part is delineating and formalizing the boundaries between them. For example, a worker running in Puma might instantiate and call three or four or a dozen different service objects all within different engines to accomplish what it needs, but all of that runs in the same Sidekiq thread.
Inserting HTTP or gRPC requests between layers might enforce clean logical boundaries but often what you end up with is a distributed ball of mud that is harder to reason about than a single codebase.