diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c
index 8396006f5980f2afedc458ea62d1d498f085600f..4f4edc6c353bda6baba27dcab305bf161180f2b6 100644
--- a/servers/slapd/schema_init.c
+++ b/servers/slapd/schema_init.c
@@ -1323,7 +1323,10 @@ UTF8StringNormalize(
 	nvalue.bv_len = 0;
 	nvalue.bv_val = tmp.bv_val;
 
-	wasspace = 1; /* trim leading spaces */
+	/* trim leading spaces? */
+	wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
+		(( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
+
 	for( i = 0; i < tmp.bv_len; i++) {
 		if ( ASCII_SPACE( tmp.bv_val[i] )) {
 			if( wasspace++ == 0 ) {
@@ -1337,8 +1340,11 @@ UTF8StringNormalize(
 	}
 
 	if( !BER_BVISEMPTY( &nvalue ) ) {
-		if( wasspace ) {
-			/* last character was a space, trim it */
+		/* trim trailing space? */
+		if( wasspace && (
+			(( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
+			( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
+		{
 			--nvalue.bv_len;
 		}
 		nvalue.bv_val[nvalue.bv_len] = '\0';
@@ -1354,6 +1360,137 @@ UTF8StringNormalize(
 	return LDAP_SUCCESS;
 }
 
+static int
+directoryStringSubstringsMatch(
+	int *matchp,
+	slap_mask_t flags,
+	Syntax *syntax,
+	MatchingRule *mr,
+	struct berval *value,
+	void *assertedValue )
+{
+	int match = 0;
+	SubstringsAssertion *sub = assertedValue;
+	struct berval left = *value;
+	int i;
+	int priorspace=0;
+
+	if ( !BER_BVISNULL( &sub->sa_initial ) ) {
+		if ( sub->sa_initial.bv_len > left.bv_len ) {
+			/* not enough left */
+			match = 1;
+			goto done;
+		}
+
+		match = memcmp( sub->sa_initial.bv_val, left.bv_val,
+			sub->sa_initial.bv_len );
+
+		if ( match != 0 ) {
+			goto done;
+		}
+
+		left.bv_val += sub->sa_initial.bv_len;
+		left.bv_len -= sub->sa_initial.bv_len;
+
+		priorspace = ASCII_SPACE(
+			sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
+	}
+
+	if ( sub->sa_any ) {
+		for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
+			ber_len_t idx;
+			char *p;
+
+			if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
+				&& ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
+			{ 
+				/* allow next space to match */
+				left.bv_val--;
+				left.bv_len++;
+			}
+			priorspace=0;
+
+retry:
+			if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
+				continue;
+			}
+
+			if ( sub->sa_any[i].bv_len > left.bv_len ) {
+				/* not enough left */
+				match = 1;
+				goto done;
+			}
+
+			p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
+
+			if( p == NULL ) {
+				match = 1;
+				goto done;
+			}
+
+			idx = p - left.bv_val;
+
+			if ( idx >= left.bv_len ) {
+				/* this shouldn't happen */
+				return LDAP_OTHER;
+			}
+
+			left.bv_val = p;
+			left.bv_len -= idx;
+
+			if ( sub->sa_any[i].bv_len > left.bv_len ) {
+				/* not enough left */
+				match = 1;
+				goto done;
+			}
+
+			match = memcmp( left.bv_val,
+				sub->sa_any[i].bv_val,
+				sub->sa_any[i].bv_len );
+
+			if ( match != 0 ) {
+				left.bv_val++;
+				left.bv_len--;
+				goto retry;
+			}
+
+			left.bv_val += sub->sa_any[i].bv_len;
+			left.bv_len -= sub->sa_any[i].bv_len;
+
+			priorspace = ASCII_SPACE(
+				sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
+		}
+	}
+
+	if ( !BER_BVISNULL( &sub->sa_final ) ) {
+		if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
+			&& ASCII_SPACE( sub->sa_final.bv_val[0] ))
+		{ 
+			/* allow next space to match */
+			left.bv_val--;
+			left.bv_len++;
+		}
+
+		if ( sub->sa_final.bv_len > left.bv_len ) {
+			/* not enough left */
+			match = 1;
+			goto done;
+		}
+
+		match = memcmp( sub->sa_final.bv_val,
+			&left.bv_val[left.bv_len - sub->sa_final.bv_len],
+			sub->sa_final.bv_len );
+
+		if ( match != 0 ) {
+			goto done;
+		}
+	}
+
+done:
+	*matchp = match;
+	return LDAP_SUCCESS;
+}
+
 #if defined(SLAPD_APPROX_INITIALS)
 #	define SLAPD_APPROX_DELIMITER "._ "
 #	define SLAPD_APPROX_WORDLEN 2
@@ -3371,7 +3508,7 @@ static slap_mrule_defs_rec mrule_defs[] = {
 	{"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
 		SLAP_MR_SUBSTR, directoryStringSyntaxes,
-		NULL, UTF8StringNormalize, octetStringSubstringsMatch,
+		NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
 		"caseIgnoreMatch" },
 
@@ -3392,7 +3529,7 @@ static slap_mrule_defs_rec mrule_defs[] = {
 	{"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
 		SLAP_MR_SUBSTR, directoryStringSyntaxes,
-		NULL, UTF8StringNormalize, octetStringSubstringsMatch,
+		NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
 		"caseExactMatch" },
 
@@ -3578,14 +3715,14 @@ static slap_mrule_defs_rec mrule_defs[] = {
 	{"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
 		SLAP_MR_SUBSTR, NULL,
-		NULL, IA5StringNormalize, octetStringSubstringsMatch,
+		NULL, IA5StringNormalize, directoryStringSubstringsMatch,
 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
 		"caseIgnoreIA5Match" },
 
 	{"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
 		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
 		SLAP_MR_SUBSTR, NULL,
-		NULL, IA5StringNormalize, octetStringSubstringsMatch,
+		NULL, IA5StringNormalize, directoryStringSubstringsMatch,
 		octetStringSubstringsIndexer, octetStringSubstringsFilter,
 		"caseExactIA5Match" },