Hi, you can achieve something like this in multiple ways. Elegance might be a bit subjective, so I'll present 3 options and let you decide which is best for your situation.
1. Toolset Access Post Groups
If you use Toolset Access's Post Groups, you can assign each individual post in this CPT to a Post Group. Then you can apply restrictions in Toolset Access per Group, per User Role. You would have to create custom User Roles for each Company, and assign each User one of those corresponding roles. This allows you to restrict access to an entire URL. In other words, restricted Users would see a 404 error if they tried to visit a post that belonged to a Post Group to which they did not have access.
This approach, isn't integrated into the approach you've already got implemented with a series of post relationships dictating access to posts in a nested View scenario. Access Post Groups do not directly restrict the results shown in a View, so you would have to rework those Views to restrict Access based on those post groups using some custom conditionals - https://toolset.com/documentation/user-guides/views/using-access-to-hide-certain-posts-from-view-results/.
However, it is the only approach that will show a true 404 error when someone visits a restricted post.
2. Nested Views in the Content Template applied to the Project post
This is basically an extension of the approach you've already used to determine whether or not to display each Project post in a View. I assume Company is a parent of Project, in a one-to-many (O2M) relationship. I also assume Company is a parent of Profiles in another O2M relationship. If so, you need at least two Views and two Content Templates here.
Content Template 1: A new template, assigned to the Project post type. This should be applied to the Project post type instead of your current template. Include the shortcode for View 2 in this template, as described below.
Content Template 2: Your current Project post type template, but unassigned from the Project Post Type. This will be used inside a nested View to display the Project to the appropriate viewers.
View 1: A View of Profiles filtered by post relationship (to Company) where Company ID is set by a shortcode attribute "wpvrelatedto", and also filtered by post author, where the author is the same as the current User. Set a limit of 1 result in this View. In the Loop, insert Content Template 2 using a shortcode and the $current_page operator to display the contents of the current Project:
[wpv-post-body view_template="content-template-2-slug" item="$current_page"]
Replace content-template-2-slug with the slug of Content Template 2. This will effectively display the current Project in your original template, but only if the current User is the author of a Profile post that belongs to the current Project post's parent Company post.
View 2: A View of Companies filtered by post ID, where the post ID is set by a shortcode attribute "ids". Set a limit of 1 on this View.
In the Loop, insert a shortcode to display View 1 and include the current Company ID in the wpvrelatedto shortcode attribute like so:
[wpv-view name="your-view-1-slug" wpvrelatedto="[wpv-post-id]"]
Replace your-view-1-slug with the slug of View 1.
Insert View 2 in Content Template 1 and pass the parent Company post ID into that View using a shortcode attribute and the wpv-post-id shortcode, like so:
[wpv-view name="view-2-slug" ids="[wpv-post-id item='@company-project-slug.parent']"]
Replace view-2-slug with the slug of View 2, and replace company-project-slug with the slug of the post relationship between Company and Project. You can find the slug in Toolset > Relationships when you edit the relationship.
3. Custom PHP function in a conditional
Use custom PHP to write a function that determines whether or not the current User should be able to see the current Project post. Use Post Relationships APIs like toolset_get_related_post or toolset_get_related_posts to query related posts and return some value like 1 or 0 to determine whether or not to show the contents inside a conditional block or conditional shortcode. Obviously this approach requires knowledge of PHP:
https://toolset.com/documentation/programmer-reference/views/using-custom-functions-in-conditions/
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_get_related_post
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_get_related_posts
So options 1 and 3 require more understanding of code. Option 2 is somewhat convoluted, but can be accomplished within wp-admin without extra PHP programming.
Let me know if you have questions about these approaches.