I offer a minor change to the constructor of HasManyAssociation, which allows you to pass in a function to filter the store. The function will take the record for which the association is being constructed, and will return a function that is suitable for filtering (i.e., the result function takes a record and returns true or false).

Here's how you might use it to define a relation where a contact is either the sender or the receiver of a message object. The relation is "contact hasMany messages":

Code:
hasMany: {
  filterProperty: function(contact) {
    return function(message) {
      return [message.get('sender_key'), message.get('recipient_key')].indexOf(contact.get('key')) > -1;
    }
  }
}
This is the override I used to achieve this:

Code:
Ext.override(Ext.data.HasManyAssociation, {
    createStore: function() {
        var that            = this,
            associatedModel = that.associatedModel,
            storeName       = that.storeName,
            foreignKey      = that.foreignKey,
            primaryKey      = that.primaryKey,
            filterProperty  = that.filterProperty,
            autoLoad        = that.autoLoad,
            storeConfig     = that.storeConfig || {};
        
        return function() {
            var me = this,
                config, filter,
                modelDefaults = {};
                
            if (me[storeName] === undefined) {
                if (filterProperty) {
                    if(filterProperty instanceof Function) {
                        console.log('filterProperty instanceof Function');
                        filter = {
                            filterFn: filterProperty(me)
                        };
                    } else {
                        filter = {
                            property  : filterProperty,
                            value     : me.get(filterProperty),
                            exactMatch: true
                        };
                    }
                } else {
                    filter = {
                        property  : foreignKey,
                        value     : me.get(primaryKey),
                        exactMatch: true
                    };
                }
                
                modelDefaults[foreignKey] = me.get(primaryKey);
                
                config = Ext.apply({}, storeConfig, {
                    model        : associatedModel,
                    filters      : [filter],
                    remoteFilter : false,
                    modelDefaults: modelDefaults
                });
                
                me[storeName] = Ext.create('Ext.data.Store', config);
                if (autoLoad) {
                    me[storeName].load();
                }
            }
            
            return me[storeName];
        };
    },
});