diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c
index 1a8d5fb..ffd3087 100644
--- a/libempathy/empathy-tp-contact-factory.c
+++ b/libempathy/empathy-tp-contact-factory.c
@@ -54,6 +54,8 @@ typedef struct {
 	guint           avatar_max_size;
 	gboolean        can_request_ft;
 	gboolean        can_request_st;
+	/* TRUE if ContactCapabilities is implemented by the Connection */
+	gboolean        contact_caps_supported;
 } EmpathyTpContactFactoryPriv;
 
 G_DEFINE_TYPE (EmpathyTpContactFactory, empathy_tp_contact_factory, G_TYPE_OBJECT);
@@ -684,11 +686,15 @@ get_requestable_channel_classes_cb (TpProxy *connection,
 
 		caps = empathy_contact_get_capabilities (contact);
 
-		if (priv->can_request_ft)
-			caps |= EMPATHY_CAPABILITIES_FT;
+		if (!priv->contact_caps_supported) {
+			/* ContactCapabilities is not supported; assume all contacts can do file
+			 * transfer if it's implemented in the CM */
+			if (priv->can_request_ft)
+				caps |= EMPATHY_CAPABILITIES_FT;
 
-		if (priv->can_request_st)
-			caps |= EMPATHY_CAPABILITIES_STREAM_TUBE;
+			if (priv->can_request_st)
+				caps |= EMPATHY_CAPABILITIES_STREAM_TUBE;
+		}
 
 		empathy_contact_set_capabilities (contact, caps);
 	}
@@ -725,6 +731,78 @@ tp_contact_factory_got_avatar_requirements_cb (TpConnection *proxy,
 }
 
 static void
+update_contact_capabilities (EmpathyTpContactFactory *self,
+			     GHashTable *caps)
+{
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_hash_table_iter_init (&iter, caps);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		TpHandle handle = GPOINTER_TO_UINT (key);
+		GPtrArray *classes = value;
+		guint i;
+		EmpathyContact *contact;
+		EmpathyCapabilities  capabilities;
+
+		contact = tp_contact_factory_find_by_handle (self, handle);
+		if (contact == NULL)
+			continue;
+
+		capabilities = empathy_contact_get_capabilities (contact);
+		capabilities &= ~EMPATHY_CAPABILITIES_UNKNOWN;
+
+		for (i = 0; i < classes->len; i++) {
+			GValueArray *class_struct;
+			GHashTable *fixed_prop;
+			TpHandleType handle_type;
+			const gchar *chan_type;
+
+			class_struct = g_ptr_array_index (classes, i);
+			fixed_prop = g_value_get_boxed (g_value_array_get_nth (class_struct, 0));
+
+			handle_type = tp_asv_get_uint32 (fixed_prop,
+				TP_IFACE_CHANNEL ".TargetHandleType", NULL);
+			if (handle_type != TP_HANDLE_TYPE_CONTACT)
+				continue;
+
+			chan_type = tp_asv_get_string (fixed_prop,
+				TP_IFACE_CHANNEL ".ChannelType");
+
+			if (!tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER))
+				capabilities |= EMPATHY_CAPABILITIES_FT;
+
+			if (!tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+				capabilities |= EMPATHY_CAPABILITIES_STREAM_TUBE;
+		}
+
+		DEBUG ("Changing capabilities for contact %s (%d) to %d",
+			empathy_contact_get_id (contact),
+			empathy_contact_get_handle (contact),
+			capabilities);
+
+		empathy_contact_set_capabilities (contact, capabilities);
+	}
+}
+
+static void
+tp_contact_factory_got_contact_capabilities (TpConnection *connection,
+					     GHashTable *caps,
+					     const GError *error,
+					     gpointer user_data,
+					     GObject *weak_object)
+{
+	EmpathyTpContactFactory *self = EMPATHY_TP_CONTACT_FACTORY (weak_object);
+
+	if (error != NULL) {
+		DEBUG ("Error: %s", error->message);
+		return;
+	}
+
+	update_contact_capabilities (self, caps);
+}
+
+static void
 tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
 				EmpathyContact          *contact)
 {
@@ -748,13 +826,17 @@ tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
 	caps = empathy_contact_get_capabilities (contact);
 
 	/* Set the FT capability */
-	if (priv->can_request_ft) {
-		caps |= EMPATHY_CAPABILITIES_FT;
-	}
+	if (!priv->contact_caps_supported) {
+		/* ContactCapabilities is not supported; assume all contacts can do file
+		 * transfer if it's implemented in the CM */
+		if (priv->can_request_ft) {
+			caps |= EMPATHY_CAPABILITIES_FT;
+		}
 
-	/* Set the Stream Tube capability */
-	if (priv->can_request_st) {
-		caps |= EMPATHY_CAPABILITIES_STREAM_TUBE;
+		/* Set the Stream Tube capability */
+		if (priv->can_request_st) {
+			caps |= EMPATHY_CAPABILITIES_STREAM_TUBE;
+		}
 	}
 
 	empathy_contact_set_capabilities (contact, caps);
@@ -794,6 +876,13 @@ tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
 									 NULL);
 	}
 
+	if (priv->contact_caps_supported) {
+		tp_cli_connection_interface_contact_capabilities_call_get_contact_capabilities (
+			priv->connection, -1, &handles,
+			tp_contact_factory_got_contact_capabilities, NULL, NULL,
+			G_OBJECT (tp_factory));
+	}
+
 	DEBUG ("Contact added: %s (%d)",
 		empathy_contact_get_id (contact),
 		empathy_contact_get_handle (contact));
@@ -1308,6 +1397,17 @@ tp_contact_factory_finalize (GObject *object)
 }
 
 static void
+tp_contact_factory_contact_capabilities_changed_cb (TpConnection *connection,
+						    GHashTable *caps,
+						    gpointer user_data,
+						    GObject *weak_object)
+{
+	EmpathyTpContactFactory *self = EMPATHY_TP_CONTACT_FACTORY (weak_object);
+
+	update_contact_capabilities (self, caps);
+}
+
+static void
 connection_ready_cb (TpConnection *connection,
 				const GError *error,
 				gpointer user_data)
@@ -1342,6 +1442,14 @@ connection_ready_cb (TpConnection *connection,
 									   G_OBJECT (tp_factory),
 									   NULL);
 
+	if (tp_proxy_has_interface_by_id (connection,
+				TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_CAPABILITIES)) {
+		priv->contact_caps_supported = TRUE;
+
+		tp_cli_connection_interface_contact_capabilities_connect_to_contact_capabilities_changed (
+			priv->connection, tp_contact_factory_contact_capabilities_changed_cb,
+			NULL, NULL, G_OBJECT (tp_factory), NULL);
+	}
 
 	tp_cli_connection_interface_avatars_call_get_avatar_requirements (priv->connection,
 									  -1,
@@ -1474,6 +1582,7 @@ empathy_tp_contact_factory_init (EmpathyTpContactFactory *tp_factory)
 	tp_factory->priv = priv;
 	priv->can_request_ft = FALSE;
 	priv->can_request_st = FALSE;
+	priv->contact_caps_supported = FALSE;
 }
 
 static GHashTable *factories = NULL;
