Fundamentally you cannot do what you want without doing one or more of the following:
- Reducing the maximum bulk size that your "interface" uses.
- Reducing the number of SOQL queries that you perform synchronously.
In reducing the maximum bulk size, you can leave the user with a "synchronous" experience by having the "interface" actually do the chunking itself. This is a good idea because there are other limits you could hit (such as maximum number of SOQL query rows) in a given transaction. Your "interface" can perform each chunk in an independent transaction, thereby avoiding such problems. This works when the "interface" is a custom Salesforce or web page (and you can write the chunking orchestration in JavaScript), or some external system.
For an external system, you can have that system split the bulk transaction into pieces, or if that's not practical consider introducing some form of middleware that does this.
To reduce the SOQL queries, consider whether you could combine (at least some of) these into a single query and consider whether aggregate queries can help you avoid SOQL query row limits. If the additional data you query is typically shared between all the various records across the transaction, consider using a transaction-scoped cache of results that can be shared between trigger invocations in that transaction.
Last option I can think of is to make this processing async but ensure that each record is individually marked as having (or not) been processed and then updating the "interface" to poll data until it is all processed (or leverage a push type notification from Salesforce). Clearly this may or may not be possible depending on what the "interface" is and how much control you have over its implementation.
You must always implement your solution taking Salesforce limits into consideration, otherwise you will fall foul of issues like this.