diff --git a/src/library/CharacterManifestData.js b/src/library/CharacterManifestData.js
index ecef2a53..dd216d55 100644
--- a/src/library/CharacterManifestData.js
+++ b/src/library/CharacterManifestData.js
@@ -1,4 +1,9 @@
 import { getAsArray } from "./utils";
+import { ManifestRestrictions } from "./manifestRestrictions";
+
+/**
+ * @typedef {import('./manifestRestrictions').TraitRestriction} TraitRestriction
+ */
 
 /**
  * @typedef {Object} TextureCollectionItem
@@ -33,7 +38,7 @@ export class CharacterManifestData{
         colliderTraits,
         lipSyncTraits,
         blinkerTraits,
-        typeRestrictions,
+        traitRestrictions,
         defaultCullingLayer,
         defaultCullingDistance,
         offset,
@@ -59,7 +64,7 @@ export class CharacterManifestData{
       this.colliderTraits = getAsArray(colliderTraits);
       this.lipSyncTraits = getAsArray(lipSyncTraits);   
       this.blinkerTraits = getAsArray(blinkerTraits);   
-      this.typeRestrictions = typeRestrictions;  
+      this.traitRestrictions = traitRestrictions;
       this.defaultCullingLayer = defaultCullingLayer
       this.defaultCullingDistance = defaultCullingDistance 
       this.offset = offset;
@@ -77,23 +82,6 @@ export class CharacterManifestData{
 
       getAllTraitsGroupID();
       
-      const populateTypeRestrictions = () =>{
-        if (this.typeRestrictions){
-          for (const prop in this.typeRestrictions){
-            const typeRestrictionValues = getAsArray(this.typeRestrictions[prop]);
-            typeRestrictionValues.forEach(tr => {
-              if (this.typeRestrictions[tr] == null){
-                this.typeRestrictions[tr] = [];
-              }
-              if (this.typeRestrictions[tr].indexOf(prop) == -1){
-                this.typeRestrictions[tr].push(prop);
-              }
-            });
-          }
-        }
-      }
-      populateTypeRestrictions();
-      
       const defaultOptions = () =>{
         // Support Old configuration
         downloadOptions.vrmMeta = downloadOptions.vrmMeta || vrmMeta;
@@ -117,6 +105,7 @@ export class CharacterManifestData{
       }
       defaultOptions();
 
+      this.manifestRestrictions = new ManifestRestrictions(this);
 
       // create texture and color traits first
       this.textureTraits = [];
@@ -135,6 +124,8 @@ export class CharacterManifestData{
       this.modelTraits = [];
       this.modelTraitsMap = null;
       this.createModelTraits(traits);
+
+      this.manifestRestrictions._init()
     }
     appendManifestData(manifestData, replaceExisting){
       manifestData.textureTraits.forEach(newTextureTraitGroup => {
@@ -196,6 +187,28 @@ export class CharacterManifestData{
     getAllTraits(){
       return this.getRandomTraits(this.allTraits);
     }
+
+    /**
+     * Assumes the trait options have unique IDs;
+     * @param {string} optionID
+     */
+    getTraitOptionById(optionID){
+      return this.getAllTraitOptions().find((option)=>option.id == optionID);
+    }
+    /**
+     * Get trait options by type;
+     * @param {string} type
+    */
+    getTraitOptionsByType(type){
+      return this.getAllTraitOptions().filter((option)=>option.type == type);
+    }
+    /**
+     * Returns all ModelTrait items in an array.
+     */
+    getAllTraitOptions(){
+      return this.modelTraits.map((trait)=>trait?.getCollection()).flat();
+    }
+
     getAllBlendShapeTraits(){
       return this.modelTraits.map(traitGroup => traitGroup.getCollection()).flat().map((c)=>c.blendshapeTraits).flat().map((c)=>c?.collection).flat().filter((c)=>!!c);
     }
@@ -424,13 +437,7 @@ export class CharacterManifestData{
 
       // Updates all restricted traits for each group models
       this.modelTraits.forEach(modelTrait => {
-        modelTrait.restrictedTraits.forEach(groupTraitID => {
-          const groupModel = this.getModelGroup(groupTraitID);
-          console.log(groupModel);
-          if (groupModel){
-            groupModel.addTraitRestriction(modelTrait.trait);
-          }
-        });
+        this.manifestRestrictions.createTraitRestriction(modelTrait);
       });
     }
 
@@ -481,6 +488,11 @@ export class TraitModelsGroup{
    */
   manifestData
 
+  /**
+   * @type {TraitRestriction|undefined}
+   */
+  restrictions
+
     constructor(manifestData, options){
         const {
           trait,
@@ -490,8 +502,6 @@ export class TraitModelsGroup{
           cullingDistance, // can be undefined; if undefined, will use default from manifestData
           cullingLayer, // can be undefined; if undefined, will use default from manifestData
           collection,
-          restrictedTraits = [],
-          restrictedTypes = []
         } = options;
         this.manifestData = manifestData;
 
@@ -501,9 +511,6 @@ export class TraitModelsGroup{
         this.iconSvg = iconSvg;
         this.fullIconSvg = manifestData.getTraitIconsDirectorySvg() + iconSvg;
 
-        this.restrictedTraits = restrictedTraits;
-        this.restrictedTypes = restrictedTypes;
-
         this.cameraTarget = cameraTarget;
         this.cullingDistance = cullingDistance;
         this.cullingLayer = cullingLayer;
@@ -535,11 +542,6 @@ export class TraitModelsGroup{
         }
       });
     }
-    addTraitRestriction(traitID){
-      if (this.restrictedTraits.indexOf(traitID) == -1){
-        this.restrictedTraits.push(traitID)
-      }
-    }
 
     createCollection(itemCollection, replaceExisting = false){
       if (replaceExisting) this.collection = [];
@@ -799,6 +801,11 @@ class TraitColorsGroup{
   }
 }
 export class ModelTrait{
+  /**
+   * @type {string}
+   */
+  type
+
   blendshapeTraits = [];
   /**
    * @type {string[]}
@@ -813,15 +820,19 @@ export class ModelTrait{
    */
   traitGroup
   blendshapeTraitsMap = new Map();
+  /**
+   * @type {string[]}
+   */
+  _restrictedItems = []
   constructor(traitGroup, options){
       const {
           id,
+          type = '',
           directory,
           name,
           thumbnail,
           cullingDistance,
           cullingLayer,
-          type = [],
           textureCollection,
           blendshapeTraits,
           colorCollection,
@@ -829,6 +840,7 @@ export class ModelTrait{
           decalMeshNameTargets,
           fullDirectory,
           fullThumbnail,
+          restrictedItems
       }= options;
       this.manifestData = traitGroup.manifestData;
       this.traitGroup = traitGroup;
@@ -837,7 +849,7 @@ export class ModelTrait{
       this.id = id;
       this.directory = directory;
 
-      
+      this._restrictedItems = restrictedItems||[];
       if (fullDirectory){
         this.fullDirectory = fullDirectory
       }
@@ -882,31 +894,13 @@ export class ModelTrait{
   isRestricted(targetModelTrait){
     if (targetModelTrait == null)
       return false;
-
-    const groupTraitID = targetModelTrait.traitGroup.trait;
-    if (this.traitGroup.restrictedTraits.indexOf(groupTraitID) != -1)
-      return true;
-
-    if (this.type.length > 0 && this.manifestData.restrictedTypes > 0){
-
-      const haveCommonValue = (arr1, arr2) => {
-        if (arr1 == null || arr2 == null)
-          return false;
-        for (let i = 0; i < arr1.length; i++) {
-          if (arr2.includes(arr1[i])) {
-            return true; // Found a common value
-          }
-        }
-        return false; // No common value found
-      }
-
-      const restrictedTypes = this.manifestData.restrictedTypes;
-      const traitTypes = getAsArray(this.type);
-      traitTypes.forEach(type => {
-        return haveCommonValue(restrictedTypes[type], traitTypes)
-      });
+    if(this.traitGroup.restrictions?.isTraitAllowed(targetModelTrait.traitGroup.trait)){
+      return false;
+    }
+    if(this.traitGroup.restrictions?.isTypeAllowed(targetModelTrait.type)){
+      return false;
     }
-    return false;
+    return true
   }
   getGroupBlendShapeTraits(){
     return this.blendshapeTraits;
@@ -1147,138 +1141,4 @@ class SelectedOption{
   }
 }
 
-
-
- const getRestrictions = () => {
-
-    const traitRestrictions = templateInfo.traitRestrictions // can be null
-    const typeRestrictions = {};
-
-    for (const prop in traitRestrictions){
-
-      // create the counter restrcitions traits
-      getAsArray(traitRestrictions[prop].restrictedTraits).map((traitName)=>{
-
-        // check if the trait restrictions exists for the other trait, if not add it
-        if (traitRestrictions[traitName] == null) traitRestrictions[traitName] = {}
-        // make sure to have an array setup, if there is none, create a new empty one
-        if (traitRestrictions[traitName].restrictedTraits == null) traitRestrictions[traitName].restrictedTraits = []
-
-        // finally merge existing and new restrictions
-        traitRestrictions[traitName].restrictedTraits = [...new Set([
-          ...traitRestrictions[traitName].restrictedTraits ,
-          ...[prop]])]  // make sure to add prop as restriction
-      })
-
-      // do the same for the types
-      getAsArray(traitRestrictions[prop].restrictedTypes).map((typeName)=>{
-        //notice were adding the new data to typeRestrictions and not trait
-        if (typeRestrictions[typeName] == null) typeRestrictions[typeName] = {}
-        //create the restricted trait in this type
-        if (typeRestrictions[typeName].restrictedTraits == null) typeRestrictions[typeName].restrictedTraits = []
-
-        typeRestrictions[typeName].restrictedTraits = [...new Set([
-          ...typeRestrictions[typeName].restrictedTraits ,
-          ...[prop]])]  // make sure to add prop as restriction
-      })
-    }
-
-    // now merge defined type to type restrictions
-    for (const prop in templateInfo.typeRestrictions){
-      // check if it already exsits
-      if (typeRestrictions[prop] == null) typeRestrictions[prop] = {}
-      if (typeRestrictions[prop].restrictedTypes == null) typeRestrictions[prop].restrictedTypes = []
-      typeRestrictions[prop].restrictedTypes = [...new Set([
-        ...typeRestrictions[prop].restrictedTypes ,
-        ...getAsArray(templateInfo.typeRestrictions[prop])])]  
-
-      // now that we have setup the type restrictions, lets counter create for the other traits
-      getAsArray(templateInfo.typeRestrictions[prop]).map((typeName)=>{
-        // prop = boots
-        // typeName = pants
-        if (typeRestrictions[typeName] == null) typeRestrictions[typeName] = {}
-        if (typeRestrictions[typeName].restrictedTypes == null) typeRestrictions[typeName].restrictedTypes =[]
-        typeRestrictions[typeName].restrictedTypes = [...new Set([
-          ...typeRestrictions[typeName].restrictedTypes ,
-          ...[prop]])]  // make sure to add prop as restriction
-      })
-    }
-  }
-
-    // _filterRestrictedOptions(options){
-    //     let removeTraits = [];
-    //     for (let i =0; i < options.length;i++){
-    //       const option = options[i];
-          
-    //      //if this option is not already in the remove traits list then:
-    //      if (!removeTraits.includes(option.trait.name)){
-    //         const typeRestrictions = restrictions?.typeRestrictions;
-    //         // type restrictions = what `type` cannot go wit this trait or this type
-    //         if (typeRestrictions){
-    //           getAsArray(option.item?.type).map((t)=>{
-    //             //combine to array
-    //             removeTraits = [...new Set([
-    //               ...removeTraits , // get previous remove traits
-    //               ...findTraitsWithTypes(getAsArray(typeRestrictions[t]?.restrictedTypes)),  //get by restricted traits by types coincidence
-    //               ...getAsArray(typeRestrictions[t]?.restrictedTraits)])]  // get by restricted trait setup
-    
-    //           })
-    //         }
-    
-    //         // trait restrictions = what `trait` cannot go wit this trait or this type
-    //         const traitRestrictions = restrictions?.traitRestrictions;
-    //         if (traitRestrictions){
-    //           removeTraits = [...new Set([
-    //             ...removeTraits,
-    //             ...findTraitsWithTypes(getAsArray(traitRestrictions[option.trait.name]?.restrictedTypes)),
-    //             ...getAsArray(traitRestrictions[option.trait.name]?.restrictedTraits),
-    
-    //           ])]
-    //         }
-    //       }
-    //     }
-    
-    //     // now update uptions
-    //     removeTraits.forEach(trait => {
-    //       let removed = false;
-    //       updateCurrentTraitMap(trait, null);
-          
-    //       for (let i =0; i < options.length;i++){
-    //         // find an option with the trait name 
-    //         if (options[i].trait?.name === trait){
-    //           options[i] = {
-    //             item:null,
-    //             trait:templateInfo.traits.find((t) => t.name === trait)
-    //           }
-    //           removed = true;
-    //           break;
-    //         }
-    //       }
-    //       // if no option setup was found, add a null option to remove in case user had it added before
-    //       if (!removed){
-    //         options.push({
-    //           item:null,
-    //           trait:templateInfo.traits.find((t) => t.name === trait)
-    //         })
-    //       }
-    //     });
-       
-    //     return options;
-    // }
-
-        // const findTraitsWithTypes = (types) => {
-        //   const typeTraits = [];
-        //   for (const prop in avatar){
-        //     for (let i = 0; i < types.length; i++){
-        //       const t = types[i]
-            
-        //       if (avatar[prop].traitInfo?.type?.includes(t)){
-        //         typeTraits.push(prop);
-        //         break;
-        //       }
-        //     }
-        //   }
-        //   return typeTraits;
-        // }
- 
     
\ No newline at end of file
diff --git a/src/library/characterManager.js b/src/library/characterManager.js
index 84a64ace..d2e9ad12 100644
--- a/src/library/characterManager.js
+++ b/src/library/characterManager.js
@@ -69,8 +69,6 @@ export class CharacterManager {
       helperRoot.renderOrder = 10000;
       this.rootModel.add(helperRoot)
       this.vrmHelperRoot = helperRoot;
-
-      
     }
 
     /**
@@ -593,6 +591,73 @@ export class CharacterManager {
         console.warn(`No trait with name: ${ groupTraitID } was found.`)
       }
     }
+
+
+    /**
+     * @private
+     * Can be used to check if a trait is restricted by another trait
+     * @param {string} traitGroupID
+     * @param {string} traitID
+     * @typedef {Object} RuleResult
+     * @property {boolean} allowed - Whether the trait is allowed.
+     * @property {Object} blocking - The blocking trait information.
+     * @returns {RuleResult[]}
+     */
+    _getTraitAllowedRules(traitGroupID,traitID){
+    const isAllowAggregated = []
+      for( const trait in this.avatar){
+        const object = this.avatar[trait];
+        const isAllowed = object.traitInfo.traitGroup.restrictions?.isReverseAllowed(object.traitInfo.type,traitGroupID,object.traitInfo.id,traitID)
+        if(isAllowed && !isAllowed?.allowed){
+          isAllowAggregated.push(isAllowed)
+        }
+      }
+      return isAllowAggregated.length? isAllowAggregated:[{allowed:true,blocking:{}}]
+    }
+
+    /**
+     * INTERNAL: Checks and Remove blocking traits; Used when loading a new trait
+     * @param {string} groupTraitID 
+     * @param {string} traitID 
+     */
+    _checkRestrictionsBeforeLoad(groupTraitID,traitID){
+      const isAllowed = this._getTraitAllowedRules(groupTraitID,traitID)
+
+      if(isAllowed[0].allowed){
+        return
+      }
+      for(const rule of isAllowed){
+        if(rule.blocking.blockingTrait){
+          /**
+           * We have a trait blocking, remove it;
+           */
+          this.removeTrait(rule.blocking.blockingTrait);
+        }
+         if(rule.blocking.blockingItemId){
+          /**
+           * We have a specific item ID blocking, remove it;
+           */
+          const trait = this.manifestData.getTraitOptionById(rule.blocking.blockingItemId);
+          if(trait){
+            this.removeTrait(trait.traitGroup.trait);
+          }
+        }
+         if (rule.blocking.blockingType){
+          /*
+          * We have a specific type blocking, remove it;
+          */
+          const traits = this.manifestData.getTraitOptionsByType(rule.blocking.blockingType);
+          if(traits.length){
+            for(const prop in this.avatar){
+              if(this.avatar[prop].traitInfo.type == rule.blocking.blockingType){
+                this.removeTrait(prop);
+              }
+            }
+          }
+        }
+      }
+    }
+
     /**
      * Loads a specific trait based on group and trait IDs.
      *
@@ -609,7 +674,7 @@ export class CharacterManager {
           try {
             // Retrieve the selected trait using manifest data
             const selectedTrait = this.manifestData.getTraitOption(groupTraitID, traitID);
-
+            this._checkRestrictionsBeforeLoad(groupTraitID,traitID)
             // If the trait is found, load it into the avatar using the _loadTraits method
             if (selectedTrait) {
               await this._loadTraits(getAsArray(selectedTrait),soloView);
diff --git a/src/library/manifestRestrictions.js b/src/library/manifestRestrictions.js
new file mode 100644
index 00000000..f9cc7bdc
--- /dev/null
+++ b/src/library/manifestRestrictions.js
@@ -0,0 +1,380 @@
+import { getAsArray } from "./utils";
+
+/**
+ * @typedef {import('./CharacterManifestData').CharacterManifestData} CharacterManifestData
+ * @typedef {import('./CharacterManifestData').ModelTrait} ModelTrait
+ * @typedef {import('./CharacterManifestData').TraitModelsGroup} TraitModelsGroup
+ * */
+
+export class ManifestRestrictions {
+
+    /**
+     * @type {Record<string, {
+     *  restrictedTraits: string[];
+     *   restrictedTypes: string[];
+     * }>;}
+     */
+    traitRestrictions
+
+    /**
+     * @type {Record<string, TraitRestriction>}
+     */
+    restrictionMaps = {};
+
+    /**
+     * restrictions for specific trait items
+     * example: { 'hat-blue-02': ['pants-blue-01', 'hat-blue-03'] }
+     * @type {Map<string, Set<string>>}
+     */
+    itemRestrictions = new Map()
+
+    /**
+     * @type {CharacterManifestData}
+     */
+    manifestData
+    
+    constructor( manifestData) {
+        this.manifestData = manifestData;
+        this.traitRestrictions = manifestData.traitRestrictions || {}
+        this._validateTraitRestrictions();
+
+    }
+
+    _init(){
+        this._setupSpecificItemRestrictions()
+        this.logRules()
+    }
+
+
+    logRules = () => {
+        const log = []
+        for(const r in this.restrictionMaps){
+            const restriction = this.restrictionMaps[r]
+            restriction.restrictedTypes.size && log.push(`Trait: ${restriction.group.trait} is restrciting traits ${Array.from(restriction.restrictedTraits.values()).join(', ')}`)
+            restriction.restrictedTypes.size && log.push(`Trait: ${restriction.group.trait} also restricts types ${Array.from(restriction.restrictedTypes.values()).join(', ')}`)
+        }
+        this.itemRestrictions.forEach((v,k)=>{
+            log.push(`Item ${k} is restricting item ${Array.from(v.values()).join(', ')}`)
+        })
+        console.log(log.join('\n'))
+    }
+
+    /**
+     * @private
+     * Setup specific item restrictions
+     */ 
+    _setupSpecificItemRestrictions = () => {
+        const all = this.manifestData.getAllTraitOptions()
+        all.forEach((c)=>{
+            this.itemRestrictions.set(c.id, new Set())
+        })
+
+        for(const modelTrait of all){
+            if(!modelTrait._restrictedItems || modelTrait._restrictedItems.length == 0) {
+                continue;
+            }
+            const restrictedSpecificIds = new Set()
+
+
+            /**
+             * If item A has [B,C], then add B,C
+             */
+            for(const itemId of modelTrait._restrictedItems) {
+                const itemData = all.find((d) => d.id == itemId)
+                if(!itemData) {
+                    console.warn(`[${modelTrait.traitGroup.trait}] Restricted item ${itemId} not found`)
+                    continue;
+                }
+                restrictedSpecificIds.add(itemId)
+            }
+            this.itemRestrictions.set(modelTrait.id, restrictedSpecificIds)
+            
+                
+            /**
+             * Go over itemRestrictions and add the other item that is restricting the current trait
+             * if D has [A,B], then add D to the restrictedTraits list of A,B
+             */
+            if(restrictedSpecificIds.size > 0) {
+
+                for(const item of restrictedSpecificIds){
+                    const r = this.itemRestrictions.get(item)
+                    if(!r) continue;
+                    if(!r.has(modelTrait.id)){
+                        r.add(modelTrait.id)
+                    }
+                }
+            }
+        }
+
+        this.itemRestrictions.forEach((v,k)=>{
+            if(v.size == 0) {
+                this.itemRestrictions.delete(k)
+            }
+        })
+
+    }
+
+    /**
+     * 
+     * @param {TraitModelsGroup} group 
+     */
+    createTraitRestriction = (group) => {
+        if (this.restrictionMaps[group.trait]) {
+            return this.restrictionMaps[group.trait];
+        }
+        const restriction = new TraitRestriction(this, group);
+        group.restrictions = restriction;
+
+        this.restrictionMaps[group.trait] = restriction;
+    
+        return restriction
+    }
+
+    /**
+     * Given a list of traits, get the traits that are forbidden given the restrictions
+     * @param {string[]} traitGroups
+     */
+    getForbiddenTraits = (traitGroups) => {
+        const disallowedTraits =new Set()
+        for(const traitId in this.restrictionMaps) {
+            if(!traitGroups.includes(traitId)) {
+                continue
+            }
+        
+            const restriction = this.restrictionMaps[traitId];
+            for(const trait of restriction.restrictedTraits) {
+                disallowedTraits.add(trait)
+            }
+        }
+        return Array.from(disallowedTraits.values())
+    }
+
+    /**
+     * Given a list of traits, get the types that are forbidden given the restrictions
+     * @param {string[]} traitGroups
+     */
+    getForbiddenTypes = (traitGroups) => {
+        const disallowedTypes =new Set()
+        for(const traitId in this.restrictionMaps) {
+            if(!traitGroups.includes(traitId)) {
+                continue
+            }
+        
+            const restriction = this.restrictionMaps[traitId];
+            for(const trait of restriction.restrictedTraits) {
+                disallowedTypes.add(trait)
+            }
+        }
+        return Array.from(disallowedTypes.values())
+    }
+    /**
+     * @private
+     * Validate trait restrictions
+     */
+     _validateTraitRestrictions = () => {
+        /**
+         * @type {Record<string, {
+         *   restrictedTraits: string[];
+         *   restrictedTypes: string[];
+         *}>}
+         */
+        const traitRes = {}
+        if (this.traitRestrictions) {
+            for (const prop in this.traitRestrictions) {
+                if (traitRes[prop] == null) {
+                    traitRes[prop] = { restrictedTraits: [], restrictedTypes: [] }
+                }
+                traitRes[prop].restrictedTraits = getAsArray(this.traitRestrictions[prop].restrictedTraits).filter((t) => !!t);
+                traitRes[prop].restrictedTypes = getAsArray(this.traitRestrictions[prop].restrictedTypes).filter((t) => !!t);
+            }
+        }
+        this.traitRestrictions = traitRes
+    }
+}
+
+
+/**
+ * @typedef {Object} TraitRestrictionResult
+ * @property {boolean} allowed
+ * @property {string} blockingTrait
+ */
+/**
+ * @typedef {Object} TypeRestrictionResult
+ * @property {boolean} allowed
+ * @property {string} blockingType
+ */
+/**
+ * @typedef {Object} blockingObject
+ * @property {string} blockingTrait
+ * @property {string} blockingType
+ * @property {string} blockingItemId
+ */
+/**
+ * @typedef {Object} ItemRestrictionResult
+ * @property {boolean} allowed
+ * @property {blockingObject} blocking
+ */
+
+export class TraitRestriction {
+    /**
+     * @type {TraitModelsGroup}
+     */
+    group;
+    /**
+     * @type {Set}
+     */
+    restrictedTraits
+    /**
+     * @type {Set}
+     */
+    restrictedTypes
+
+    /**
+     * 
+     * @param {ManifestRestrictions} manifestRestrictions 
+     * @param {TraitModelsGroup} group 
+     */
+    constructor(manifestRestrictions, group) {
+        this.manifestRestrictions = manifestRestrictions;
+        this.group = group;
+
+        this.restrictedTraits = new Set(this.manifestRestrictions.traitRestrictions[group.trait]?.restrictedTraits || []);
+        this.restrictedTypes = new Set(this.manifestRestrictions.traitRestrictions[group.trait]?.restrictedTypes || []);
+
+        /**
+         * Check if the current trait is restricting another trait, if so add the current trait to the restrictedTraits list of the other trait
+         * Note that this works only because we are iterating over the traitRestrictions objects one at a time.
+         */
+        for(const traitKey in this.manifestRestrictions.traitRestrictions) {
+            if(traitKey == group.trait) {
+                continue;
+            }
+            const otherTraitRestriction = this.manifestRestrictions.traitRestrictions[traitKey]
+            /**
+             * If the current trait is restricting another trait, then add current trait to the restrictedTraits list of other key
+             */
+            for(const traitId of this.restrictedTraits) {
+                const objectFromMap =this.manifestRestrictions.restrictionMaps[traitId]
+                if(objectFromMap){
+                    if(!objectFromMap.restrictedTraits.has(group.trait)) {
+                        objectFromMap.restrictedTraits.add(traitKey);
+                    }
+                }
+            }
+            /**
+             * If the current trait is restricted by another trait, then add the current trait to the restrictedTraits list
+             */
+            if(otherTraitRestriction.restrictedTraits.includes(group.trait) && !this.restrictedTraits.has(traitKey)) {
+                this.restrictedTraits.add(traitKey);
+            }
+        }
+    }
+
+    get manifestData(){
+        return this.manifestRestrictions.manifestData;
+    }
+    
+    get traitId() {
+        return this.group.trait;
+    }
+    /**
+     * Check whether the trait ID is permitted for this trait restriction
+     * true if the trait is not in the restrictedTraits list
+     * @type {string} traitId
+     * @returns {boolean}
+     */
+    isTraitAllowed = (traitId) => {
+        return !this.restrictedTraits.has(traitId);
+    }
+    /**
+     * Check whether the type is permitted for this trait restriction
+     * true if the type is not in the restrictedTypes list
+     * @type {string} typeName
+     * @returns {boolean}
+     */
+    isTypeAllowed = (typeName) => {
+        return !this.restrictedTypes.has(typeName);
+    }
+    /**
+     * Check whether this trait restriction is allowed by target trait
+     * @param {string} targetTrait
+     * @returns {TraitRestrictionResult}
+     */
+    isReverseTraitAllowed = (targetTrait) => {
+        const restriction = this.manifestRestrictions.restrictionMaps[targetTrait];
+        if (restriction) {
+            const isAllowed = restriction.isTraitAllowed(this.traitId)
+            return {allowed:isAllowed, blockingTrait: isAllowed?undefined:this.traitId};
+        }
+
+        return {allowed:true, blockingTrait: undefined};
+    }
+    /**
+     * Check whether the type from this restriction is allowed by target trait
+     * @param {string} sourceType
+     * @param {string} targetTrait
+     * @returns {TypeRestrictionResult}
+     */
+    isReverseTypeAllowed = (sourceType,targetTrait) => {
+        if(!sourceType) return {allowed:true};
+        const restriction = this.manifestRestrictions.restrictionMaps[targetTrait];
+        if (restriction) {
+            const isAllowed = restriction.isTypeAllowed(sourceType)
+            return {allowed:isAllowed, blockingType: isAllowed?undefined:this.traitId};
+        }
+
+        return {allowed:true}
+    }
+    /**
+     * Check whether the soruceItem allows the targetItem
+     * @param {string} sourceItemId
+     * @param {string} targetItemId
+     * @returns {boolean}
+     */
+    isItemAllowed = (sourceItemId, targetItemId) => {
+        if(!sourceItemId) return true;
+        const list = this.manifestRestrictions.itemRestrictions.get(sourceItemId)
+        if (list) {
+            return !list.has(targetItemId)
+        }
+
+        return true
+    }
+
+    /**
+     * 
+     * @param {string} sourceItemId 
+     * @param {string} targetItemId 
+     * @returns {ItemRestrictionResult}
+     */ 
+    isReverseItemAllowed = (sourceItemId, targetItemId) => {
+        if(!sourceItemId) return {allowed:true, blockingItemId:undefined};
+        const list = this.manifestRestrictions.itemRestrictions.get(targetItemId)
+        if (list) {
+            const isAllowed = !list.has(sourceItemId)
+            return {allowed:isAllowed, blockingItemId: isAllowed?undefined:sourceItemId}
+        }
+
+        return {allowed:true, blockingItemId:undefined}
+    }
+    /**
+     * 
+     * @param {string} sourceType 
+     * @param {string} targetTrait 
+     * @param {string} sourceItemId 
+     * @param {string} targetItemId 
+     * @returns {ItemRestrictionResult}
+     */
+    isReverseAllowed = (sourceType,targetTrait,sourceItemId,targetItemId) => {
+
+        const isReverseTraitAllowed = this.isReverseTraitAllowed(targetTrait)
+        const isReverseTypeAllowed = this.isReverseTypeAllowed(sourceType,targetTrait)
+        const isReverseItemAllowed = this.isReverseItemAllowed(sourceItemId,targetItemId)
+
+        return {allowed:isReverseTraitAllowed.allowed && isReverseTypeAllowed.allowed && isReverseItemAllowed.allowed, blocking: {
+            blockingTrait:isReverseTraitAllowed.blockingTrait,
+            blockingType:isReverseTypeAllowed.blockingType,
+            blockingItemId:isReverseItemAllowed.blockingItemId
+        }}
+    }
+}
\ No newline at end of file