diff --git a/src/librygel-server/rygel-media-container.vala b/src/librygel-server/rygel-media-container.vala
index b5b61b3..c1130f1 100644
--- a/src/librygel-server/rygel-media-container.vala
+++ b/src/librygel-server/rygel-media-container.vala
@@ -416,4 +416,20 @@ public abstract class Rygel.MediaContainer : MediaObject {
             }
         }
     }
+
+    internal override bool satisfies (RelationalExpression relation) {
+        if ((this is TrackableContainer)
+            && (this as TrackableContainer).satisfies (relation)) {
+            return true;
+        }
+        if ((this is WritableContainer) 
+            && (this as WritableContainer).satisfies (relation)) {
+            return true;
+        }
+        if ((relation.operand1 == "@childCount")
+            && relation.compare_int (child_count)) {
+            return true;
+        }
+        return base.satisfies (relation);
+    }
 }
diff --git a/src/librygel-server/rygel-media-item.vala b/src/librygel-server/rygel-media-item.vala
index 88dc9ae..f999e04 100644
--- a/src/librygel-server/rygel-media-item.vala
+++ b/src/librygel-server/rygel-media-item.vala
@@ -105,6 +105,15 @@ public abstract class Rygel.MediaItem : MediaObject {
         this.description = didl_object.description;
     }
 
+    internal override bool satisfies (RelationalExpression relation) {
+        if (this is TrackableItem) {
+            if ((this as TrackableItem).satisfies (relation)) {
+                return true;
+            }
+        }
+        return base.satisfies (relation);
+    }
+
     internal override DIDLLiteObject? serialize (Serializer serializer,
                                                  HTTPServer http_server)
                                                  throws Error {
diff --git a/src/librygel-server/rygel-media-object.vala b/src/librygel-server/rygel-media-object.vala
index 6d9c90d..35f1814 100644
--- a/src/librygel-server/rygel-media-object.vala
+++ b/src/librygel-server/rygel-media-object.vala
@@ -417,6 +417,25 @@ public abstract class Rygel.MediaObject : GLib.Object {
         return (prop1 - prop2).clamp (-1, 1);
     }
 
+    internal virtual bool satisfies (RelationalExpression relation) {
+        switch (relation.operand1) {
+        case "@id":
+            return relation.compare_string (this.id);
+        case "@refID":
+            return relation.compare_string (this.ref_id);
+        case "@parentID":
+            return relation.compare_string (this.parent.id);
+        case "upnp:class":
+            return relation.compare_string (this.upnp_class);
+        case "dc:title":
+            return relation.compare_string (this.title);
+        case "upnp:objectUpdateID":
+            return relation.compare_uint (this.object_update_id);
+        default:
+            return false;
+        }
+    }
+
     private async bool check_writable (File file, Cancellable? cancellable)
                                        throws Error {
         // Special URI scheme to indicate that this is a writable container
diff --git a/src/librygel-server/rygel-media-server-plugin.vala b/src/librygel-server/rygel-media-server-plugin.vala
index fd0aa13..38650e4 100644
--- a/src/librygel-server/rygel-media-server-plugin.vala
+++ b/src/librygel-server/rygel-media-server-plugin.vala
@@ -53,7 +53,9 @@ public abstract class Rygel.MediaServerPlugin : Rygel.Plugin {
     public virtual string search_caps {
         get {
             if (this._search_caps == null) {
-                this._search_caps = RelationalExpression.CAPS;
+                this._search_caps = "@id,@parentID,@refID,upnp:class,"
+                                    + "dc:title,upnp:artist,upnp:album,"
+                                    + "dc:creator,@childCount";
 
                 if (PluginCapabilities.TRACK_CHANGES in this.capabilities) {
                     this._search_caps += ",upnp:objectUpdateID,upnp:containerUpdateID";
diff --git a/src/librygel-server/rygel-music-item.vala b/src/librygel-server/rygel-music-item.vala
index 700e346..99fb1e2 100644
--- a/src/librygel-server/rygel-music-item.vala
+++ b/src/librygel-server/rygel-music-item.vala
@@ -86,6 +86,23 @@ public class Rygel.MusicItem : AudioItem {
         }
     }
 
+    internal override bool satisfies (RelationalExpression relation) {
+        if ((relation.operand1 == "upnp:artist")
+            && relation.compare_string (this.artist)) {
+            return true;
+        }
+        if ((relation.operand1 == "upnp:album")
+            && relation.compare_string (this.album)) {
+            return true;
+        }
+        if (((relation.operand1 == "upnp:genre")
+             || (relation.operand1 == "dc:genre"))
+            && relation.compare_string (this.genre)) {
+            return true;
+        }
+        return base.satisfies (relation);
+    }
+
     internal override void apply_didl_lite (DIDLLiteObject didl_object) {
         base.apply_didl_lite (didl_object);
 
diff --git a/src/librygel-server/rygel-photo-item.vala b/src/librygel-server/rygel-photo-item.vala
index 1f435a6..ed40a23 100644
--- a/src/librygel-server/rygel-photo-item.vala
+++ b/src/librygel-server/rygel-photo-item.vala
@@ -57,6 +57,14 @@ public class Rygel.PhotoItem : ImageItem {
         }
     }
 
+    internal override bool satisfies (RelationalExpression relation) {
+        if ((relation.operand1 == "dc:creator")
+            && relation.compare_string (this.creator)) {
+            return true;
+        }
+        return base.satisfies (relation);
+    }
+
     private string get_first (GLib.List<DIDLLiteContributor>? contributors) {
         if (contributors != null) {
             return contributors.data.name;
diff --git a/src/librygel-server/rygel-relational-expression.vala b/src/librygel-server/rygel-relational-expression.vala
index 7d99749..a1c9b14 100644
--- a/src/librygel-server/rygel-relational-expression.vala
+++ b/src/librygel-server/rygel-relational-expression.vala
@@ -31,104 +31,14 @@ using GUPnP;
  */
 public class Rygel.RelationalExpression :
              Rygel.SearchExpression<SearchCriteriaOp,string,string> {
-    internal const string CAPS = "@id,@parentID,@refID,upnp:class," +
-                                 "dc:title,upnp:artist,upnp:album," +
-                                 "dc:creator,@childCount";
-
     public override bool satisfied_by (MediaObject media_object) {
-        switch (this.operand1) {
-        case "@id":
-            return this.compare_string (media_object.id);
-        case "@refID":
-            return this.compare_string (media_object.ref_id);
-        case "@parentID":
-            return this.compare_string (media_object.parent.id);
-        case "upnp:class":
-            return this.compare_string (media_object.upnp_class);
-        case "dc:title":
-            return this.compare_string (media_object.title);
-        case "upnp:objectUpdateID":
-            if (this.op == SearchCriteriaOp.EXISTS) {
-                if (this.operand2 == "true") {
-                    return media_object is TrackableContainer ||
-                           media_object is TrackableItem;
-                } else {
-                    return !(media_object is TrackableContainer ||
-                             media_object is TrackableItem);
-                }
-            } else {
-                return this.compare_uint (media_object.object_update_id);
-            }
-        case "upnp:containerUpdateID":
-            if (!(media_object is MediaContainer)) {
-                return false;
-            }
-
-            if (this.op == SearchCriteriaOp.EXISTS) {
-                if (this.operand2 == "true") {
-                    return media_object is TrackableContainer;
-                } else {
-                    return !(media_object is TrackableContainer);
-                }
-            } else {
-                var container = media_object as MediaContainer;
-                return this.compare_uint (container.update_id);
-            }
-        case "upnp:createClass":
-            if (!(media_object is WritableContainer)) {
-                return false;
-            }
-
-            return this.compare_create_class
-                                        (media_object as WritableContainer);
-        case "dc:creator":
-            if (!(media_object is PhotoItem)) {
-                return false;
-            }
-
-            return this.compare_string ((media_object as PhotoItem).creator);
-        case "upnp:artist":
-            if (!(media_object is MusicItem)) {
-                return false;
-            }
-
-            return this.compare_string ((media_object as MusicItem).artist);
-        case "upnp:album":
-            if (!(media_object is MusicItem)) {
-                return false;
-            }
-
-            return this.compare_string ((media_object as MusicItem).album);
-        case "@childCount":
-            if (!(media_object is MediaContainer)) {
-                return false;
-            }
-
-            var container = media_object as MediaContainer;
-            return this.compare_int (container.child_count);
-        default:
-            return false;
-        }
+        return media_object.satisfies (this);
     }
 
     public override string to_string () {
         return "%s %d %s".printf (this.operand1, this.op, this.operand2);
     }
 
-    private bool compare_create_class (WritableContainer container) {
-        var ret = false;
-
-        foreach (var create_class in container.create_classes) {
-            if (this.compare_string (create_class)) {
-                ret = true;
-
-                break;
-            }
-        }
-
-        return ret;
-    }
-
     public bool compare_string (string? str) {
         var up_operand2 = this.operand2.up ();
         string up_str;
diff --git a/src/librygel-server/rygel-trackable-container.vala b/src/librygel-server/rygel-trackable-container.vala
index 60b4799..81ba77d 100644
--- a/src/librygel-server/rygel-trackable-container.vala
+++ b/src/librygel-server/rygel-trackable-container.vala
@@ -18,6 +18,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+using GUPnP;
+
 /**
  * The base class for containers that provide automatic change tracking.
  *
@@ -158,4 +160,10 @@ public interface Rygel.TrackableContainer : Rygel.MediaContainer {
     private void thaw_events () {
         // Forward events.
     }
+
+    public bool satisfies (RelationalExpression relation) {
+        return ((relation.operand1 == "upnp:objectUpdateID")
+                && (relation.op == SearchCriteriaOp.EXISTS)
+                && (relation.operand2 == "true"));
+    }
 }
diff --git a/src/librygel-server/rygel-trackable-item.vala b/src/librygel-server/rygel-trackable-item.vala
index 9b11429..129980e 100644
--- a/src/librygel-server/rygel-trackable-item.vala
+++ b/src/librygel-server/rygel-trackable-item.vala
@@ -18,10 +18,18 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+using GUPnP;
+
 public interface Rygel.TrackableItem : Rygel.MediaItem {
     public void changed () {
         if (this.parent != null) {
             this.parent.updated (this);
         }
     }
+
+    public bool satisfies (RelationalExpression relation) {
+        return ((relation.operand1 == "upnp:objectUpdateID")
+                && (relation.op == SearchCriteriaOp.EXISTS)
+                && (relation.operand2 == "true"));
+    }
 }
diff --git a/src/librygel-server/rygel-video-item.vala b/src/librygel-server/rygel-video-item.vala
index e517b5e..6aa337b 100644
--- a/src/librygel-server/rygel-video-item.vala
+++ b/src/librygel-server/rygel-video-item.vala
@@ -58,6 +58,8 @@ public class Rygel.VideoItem : AudioItem, VisualItem {
      */
     public int color_depth { get; set; default = -1; }
 
+    public string genre { get; set; }
+
     /**
      * Thumbnail pictures to represent the video.
      */
@@ -113,6 +115,15 @@ public class Rygel.VideoItem : AudioItem, VisualItem {
         }
     }
 
+    internal override bool satisfies (RelationalExpression relation) {
+        if (((relation.operand1 == "upnp:genre")
+             || (relation.operand1 == "dc:genre"))
+            && relation.compare_string (this.genre)) {
+            return true;
+        }
+        return base.satisfies (relation);
+    }
+
     private string get_first (GLib.List<DIDLLiteContributor>? contributors) {
         if (contributors != null) {
             return contributors.data.name;
diff --git a/src/librygel-server/rygel-writable-container.vala b/src/librygel-server/rygel-writable-container.vala
index 9229015..486fd19 100644
--- a/src/librygel-server/rygel-writable-container.vala
+++ b/src/librygel-server/rygel-writable-container.vala
@@ -141,4 +141,17 @@ public interface Rygel.WritableContainer : MediaContainer {
     public async abstract void remove_container (string       id,
                                                  Cancellable? cancellable)
                                                  throws Error;
+
+    public bool satisfies (RelationalExpression relation) {
+        var ret = false;
+
+        foreach (var create_class in this.create_classes) {
+            if (relation.compare_string (create_class)) {
+                ret = true;
+                break;
+            }
+        }
+
+        return ret;
+    }
 }
