Per the documentation
When filters are executed
In templates, filters are only executed when their inputs have changed. This is more performant than executing a filter on each $digest as is the case with expressions.
There are two exceptions to this rule:
In general, this applies only to filters that take primitive values as inputs. Filters that receive Objects as input are executed on each $digest, as it would be too costly to track if the inputs have changed.
Filters that are marked as $stateful are also executed on each $digest. See Stateful filters for more information. Note that no Angular core filters are $stateful.
So in your case, so long as details.client.Id isn't triggered from some input's change event or isn't triggering a digest, your filter is running as performant as it can be.
Another way would be to call a controller method that has a cached value. It won't prevent the filter from firing, but it will immediately return a cached value. I don't recommend this though because angular filters are generally the prescribed solution for performant filtering solutions.
controller method
$scope.getCached = function(){
if(cachedValue) return cachedValue
return cachedValue = ...
}
implementation
<div ng-repeat="obj in objs | filter:getCached()">