diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
index 822d5f2e16e36..1602f4b90e094 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
@@ -17,6 +17,7 @@ import android.graphics.Rect;
 import android.os.Build;
 import android.os.Build.VERSION;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.os.SystemClock;
@@ -54,11 +55,13 @@ import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.MetricsUtils;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.components.autofill.AutofillHintsServiceTestHelper;
 import org.chromium.components.autofill.AutofillManagerWrapper;
 import org.chromium.components.autofill.AutofillPopup;
 import org.chromium.components.autofill.AutofillProvider;
 import org.chromium.components.autofill.AutofillProviderTestHelper;
 import org.chromium.components.autofill.AutofillProviderUMA;
+import org.chromium.components.autofill_public.ViewType;
 import org.chromium.components.embedder_support.util.WebResourceResponseInfo;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.content_public.browser.test.util.DOMUtils;
@@ -2112,6 +2115,10 @@ public class AwAutofillTest {
                         "crowdsourcing-autofill-hints"));
         assertEquals("HTML_TYPE_EMAIL",
                 viewStructure.getChild(1).getHtmlInfo().getAttribute("computed-autofill-hints"));
+
+        // Binder will not be set if the prediction already arrives.
+        IBinder binder = viewStructure.getExtras().getBinder("AUTOFILL_HINTS_SERVICE");
+        assertNull(binder);
     }
 
     @Test
@@ -2130,6 +2137,68 @@ public class AwAutofillTest {
         executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
         dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
 
+        cnt += waitForCallbackAndVerifyTypes(cnt,
+                new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED,
+                        AUTOFILL_VALUE_CHANGED});
+
+        invokeOnProvideAutoFillVirtualStructure();
+        TestViewStructure viewStructure = mTestValues.testViewStructure;
+        assertNotNull(viewStructure);
+        assertEquals(2, viewStructure.getChildCount());
+        assertEquals("NO_SERVER_DATA",
+                viewStructure.getChild(0).getHtmlInfo().getAttribute(
+                        "crowdsourcing-autofill-hints"));
+        assertEquals("UNKNOWN_TYPE",
+                viewStructure.getChild(0).getHtmlInfo().getAttribute("computed-autofill-hints"));
+        assertEquals("NO_SERVER_DATA",
+                viewStructure.getChild(1).getHtmlInfo().getAttribute(
+                        "crowdsourcing-autofill-hints"));
+        assertEquals("HTML_TYPE_EMAIL",
+                viewStructure.getChild(1).getHtmlInfo().getAttribute("computed-autofill-hints"));
+
+        IBinder binder = viewStructure.getExtras().getBinder("AUTOFILL_HINTS_SERVICE");
+        assertNotNull(binder);
+        AutofillHintsServiceTestHelper autofillHintsServiceTestHelper =
+                new AutofillHintsServiceTestHelper();
+        autofillHintsServiceTestHelper.registerViewTypeService(binder);
+
+        TestThreadUtils.runOnUiThreadBlocking(
+                ()
+                        -> AutofillProviderTestHelper
+                                   .simulateMainFrameAutofillServerResponseForTesting(
+                                           mAwContents.getWebContents(),
+                                           new String[] {"text1", "text2"},
+                                           new int[] {/*USERNAME, EMAIL_ADDRESS*/ 86, 9}));
+
+        cnt += waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_QUERY_DONE});
+        assertTrue(mTestAutofillManagerWrapper.isQuerySucceed());
+        autofillHintsServiceTestHelper.waitForCallbackInvoked();
+        List<ViewType> viewTypes = autofillHintsServiceTestHelper.getViewTypes();
+        assertEquals(2, viewTypes.size());
+        assertEquals(viewStructure.getChild(0).getAutofillId(), viewTypes.get(0).mAutofillId);
+        assertEquals("USERNAME", viewTypes.get(0).mServerType);
+        assertEquals("USERNAME", viewTypes.get(0).mComputedType);
+        assertEquals(viewStructure.getChild(1).getAutofillId(), viewTypes.get(1).mAutofillId);
+        assertEquals("EMAIL_ADDRESS", viewTypes.get(1).mServerType);
+        assertEquals("HTML_TYPE_EMAIL", viewTypes.get(1).mComputedType);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add({"enable-features=AndroidAutofillQueryServerFieldTypes"})
+    public void testServerPredictionArrivesBeforeCallbackRegistered() throws Throwable {
+        final String data = "<html><head></head><body><form action='a.html' name='formname'>"
+                + "<input type='text' id='text1' name='username'>"
+                + "<input type='text' name='email' id='text2' autocomplete='email'/>"
+                + "</form></body></html>";
+        final String url = mWebServer.setResponse(FILE, data, null);
+        loadUrlSync(url);
+
+        int cnt = 0;
+        executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
+        dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
+
         cnt += waitForCallbackAndVerifyTypes(cnt,
                 new Integer[] {AUTOFILL_CANCEL, AUTOFILL_VIEW_ENTERED, AUTOFILL_SESSION_STARTED,
                         AUTOFILL_VALUE_CHANGED});
@@ -2160,7 +2229,20 @@ public class AwAutofillTest {
         cnt += waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_QUERY_DONE});
         assertTrue(mTestAutofillManagerWrapper.isQuerySucceed());
 
-        // TODO(crbug.com/1151542): Verify the field types once they are sent from service.
+        IBinder binder = viewStructure.getExtras().getBinder("AUTOFILL_HINTS_SERVICE");
+        assertNotNull(binder);
+        AutofillHintsServiceTestHelper autofillHintsServiceTestHelper =
+                new AutofillHintsServiceTestHelper();
+        autofillHintsServiceTestHelper.registerViewTypeService(binder);
+        autofillHintsServiceTestHelper.waitForCallbackInvoked();
+        List<ViewType> viewTypes = autofillHintsServiceTestHelper.getViewTypes();
+        assertEquals(2, viewTypes.size());
+        assertEquals(viewStructure.getChild(0).getAutofillId(), viewTypes.get(0).mAutofillId);
+        assertEquals("USERNAME", viewTypes.get(0).mServerType);
+        assertEquals("USERNAME", viewTypes.get(0).mComputedType);
+        assertEquals(viewStructure.getChild(1).getAutofillId(), viewTypes.get(1).mAutofillId);
+        assertEquals("EMAIL_ADDRESS", viewTypes.get(1).mServerType);
+        assertEquals("HTML_TYPE_EMAIL", viewTypes.get(1).mComputedType);
     }
 
     @Test
@@ -2193,8 +2275,8 @@ public class AwAutofillTest {
         assertNull(viewStructure.getChild(1).getHtmlInfo().getAttribute(
                 "crowdsourcing-autofill-hints"));
         assertNull(viewStructure.getChild(1).getHtmlInfo().getAttribute("computed-autofill-hints"));
-
-        // TODO(crbug.com/1151542): Complete the test once the prediction update is implemented.
+        IBinder binder = viewStructure.getExtras().getBinder("AUTOFILL_HINTS_SERVICE");
+        assertNull(binder);
     }
 
     @Test
@@ -2232,6 +2314,12 @@ public class AwAutofillTest {
         assertEquals("HTML_TYPE_EMAIL",
                 viewStructure.getChild(1).getHtmlInfo().getAttribute("computed-autofill-hints"));
 
+        IBinder binder = viewStructure.getExtras().getBinder("AUTOFILL_HINTS_SERVICE");
+        assertNotNull(binder);
+        AutofillHintsServiceTestHelper autofillHintsServiceTestHelper =
+                new AutofillHintsServiceTestHelper();
+        autofillHintsServiceTestHelper.registerViewTypeService(binder);
+
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
                         -> AutofillProviderTestHelper
@@ -2240,6 +2328,9 @@ public class AwAutofillTest {
 
         cnt += waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_QUERY_DONE});
         assertFalse(mTestAutofillManagerWrapper.isQuerySucceed());
+
+        autofillHintsServiceTestHelper.waitForCallbackInvoked();
+        assertTrue(autofillHintsServiceTestHelper.isQueryFailed());
     }
 
     private void pollJavascriptResult(String script, String expectedResult) throws Throwable {
diff --git a/components/autofill/android/provider/BUILD.gn b/components/autofill/android/provider/BUILD.gn
index f3b3284f7b822..a6de523a5fd36 100644
--- a/components/autofill/android/provider/BUILD.gn
+++ b/components/autofill/android/provider/BUILD.gn
@@ -29,6 +29,7 @@ android_library("java") {
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
   sources = [
     "java/src/org/chromium/components/autofill/AutofillActionModeCallback.java",
+    "java/src/org/chromium/components/autofill/AutofillHintsService.java",
     "java/src/org/chromium/components/autofill/AutofillManagerWrapper.java",
     "java/src/org/chromium/components/autofill/AutofillProvider.java",
     "java/src/org/chromium/components/autofill/AutofillProviderUMA.java",
diff --git a/components/autofill/android/provider/autofill_provider_android.cc b/components/autofill/android/provider/autofill_provider_android.cc
index d897165dabb80..652a4fe4ce0ab 100644
--- a/components/autofill/android/provider/autofill_provider_android.cc
+++ b/components/autofill/android/provider/autofill_provider_android.cc
@@ -159,7 +159,7 @@ void AutofillProviderAndroid::MaybeStartNewSession(
   Java_AutofillProvider_startAutofillSession(
       env, obj, form_obj, index, transformed_bounding.x(),
       transformed_bounding.y(), transformed_bounding.width(),
-      transformed_bounding.height());
+      transformed_bounding.height(), handler->has_server_prediction());
 }
 
 void AutofillProviderAndroid::OnAutofillAvailable(JNIEnv* env,
diff --git a/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java b/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java
new file mode 100644
index 0000000000000..14fd7b0e73eb8
--- /dev/null
+++ b/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillHintsService.java
@@ -0,0 +1,74 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.os.IBinder;
+
+import org.chromium.base.Log;
+import org.chromium.components.autofill_public.IAutofillHintsService;
+import org.chromium.components.autofill_public.IViewTypeCallback;
+import org.chromium.components.autofill_public.ViewType;
+
+import java.util.List;
+
+/**
+ * This class is used to talk to autofill service about the view type.
+ */
+public class AutofillHintsService {
+    private static final String TAG = "AutofillHintsService";
+
+    public AutofillHintsService() {
+        mBinder = new IAutofillHintsService.Stub() {
+            @Override
+            public void registerViewTypeCallback(IViewTypeCallback callback) {
+                mCallback = callback;
+                if (mUnsentViewTypes != null) {
+                    invokeOnViewTypeAvailable();
+                } else if (mQueryFailed != null) {
+                    invokeOnQueryFailed();
+                }
+            }
+        };
+    }
+
+    public IBinder getBinder() {
+        return mBinder;
+    }
+
+    public void onViewTypeAvailable(List<ViewType> viewTypes) {
+        if (mUnsentViewTypes != null) return;
+        mUnsentViewTypes = viewTypes;
+        if (mCallback == null) return;
+        invokeOnViewTypeAvailable();
+    }
+
+    public void onQueryFailed() {
+        if (mQueryFailed != null) return;
+        mQueryFailed = Boolean.TRUE;
+        if (mCallback == null) return;
+        invokeOnQueryFailed();
+    }
+
+    private void invokeOnViewTypeAvailable() {
+        try {
+            mCallback.onViewTypeAvailable(mUnsentViewTypes);
+        } catch (Exception e) {
+            Log.e(TAG, "onViewTypeAvailable ", e);
+        }
+    }
+
+    private void invokeOnQueryFailed() {
+        try {
+            mCallback.onQueryFailed();
+        } catch (Exception e) {
+            Log.e(TAG, "onQueryFailed ", e);
+        }
+    }
+
+    private IAutofillHintsService.Stub mBinder;
+    private IViewTypeCallback mCallback;
+    private List<ViewType> mUnsentViewTypes;
+    private Boolean mQueryFailed;
+}
diff --git a/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java b/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
index d98148cd33ee2..6326536d41f87 100644
--- a/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
+++ b/components/autofill/android/provider/java/src/org/chromium/components/autofill/AutofillProvider.java
@@ -28,6 +28,7 @@ import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.base.annotations.VerifiesOnO;
 import org.chromium.base.metrics.ScopedSysTraceEvent;
+import org.chromium.components.autofill_public.ViewType;
 import org.chromium.components.version_info.VersionConstants;
 import org.chromium.content_public.browser.RenderCoordinates;
 import org.chromium.content_public.browser.WebContents;
@@ -37,6 +38,8 @@ import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
 
+import java.util.ArrayList;
+
 /**
  * This class works with Android autofill service to fill web form, it doesn't use chrome's
  * autofill service or suggestion UI. All methods are supposed to be called in UI thread.
@@ -58,6 +61,9 @@ import org.chromium.ui.display.DisplayAndroid;
 @JNINamespace("autofill")
 public class AutofillProvider {
     private static final String TAG = "AutofillProvider";
+
+    // This member is initialize at first use. Not access it directly, always through
+    // isQueryServerFieldTypesEnabled().
     private static Boolean sIsQueryServerFieldTypesEnabled;
 
     private static class FocusField {
@@ -83,11 +89,19 @@ public class AutofillProvider {
         public final int sessionId;
         private FormData mFormData;
         private FocusField mFocusField;
+        private AutofillHintsService mAutofillHintsService;
 
-        public AutofillRequest(FormData formData, FocusField focus) {
+        /**
+         * @param formData the form of the AutofillRequest.
+         * @param focus the current focused field.
+         * @param hasServerPrediction whether the server type of formData is valid.
+         */
+        public AutofillRequest(FormData formData, FocusField focus, boolean hasServerPrediction) {
             sessionId = getNextClientId();
             mFormData = formData;
             mFocusField = focus;
+            // Don't need to create binder object if server prediction is already available.
+            if (!hasServerPrediction) mAutofillHintsService = new AutofillHintsService();
         }
 
         public void fillViewStructure(ViewStructure structure) {
@@ -101,6 +115,7 @@ public class AutofillProvider {
                 ViewStructure child = structure.newChild(index++);
                 int virtualId = toVirtualId(sessionId, fieldIndex++);
                 child.setAutofillId(structure.getAutofillId(), virtualId);
+                field.setAutofillId(child.getAutofillId());
                 if (field.mAutocompleteAttr != null && !field.mAutocompleteAttr.isEmpty()) {
                     child.setAutofillHints(field.mAutocompleteAttr.split(" +"));
                 }
@@ -256,6 +271,24 @@ public class AutofillProvider {
         private static int toVirtualId(int clientId, short index) {
             return (clientId << 16) | index;
         }
+
+        public AutofillHintsService getAutofillHintsService() {
+            return mAutofillHintsService;
+        }
+
+        public void onQueryDone(boolean success) {
+            if (mAutofillHintsService == null) return;
+            if (success) {
+                ArrayList<ViewType> viewTypes = new ArrayList<ViewType>();
+                for (FormFieldData field : mFormData.mFields) {
+                    viewTypes.add(new ViewType(
+                            field.getAutofillId(), field.getServerType(), field.getComputedType()));
+                }
+                mAutofillHintsService.onViewTypeAvailable(viewTypes);
+            } else {
+                mAutofillHintsService.onQueryFailed();
+            }
+        }
     }
 
     private final String mProviderName;
@@ -328,6 +361,13 @@ public class AutofillProvider {
             bundle.putCharSequence("VIRTUAL_STRUCTURE_PROVIDER_NAME", mProviderName);
             bundle.putCharSequence(
                     "VIRTUAL_STRUCTURE_PROVIDER_VERSION", VersionConstants.PRODUCT_VERSION);
+
+            if (isQueryServerFieldTypesEnabled()) {
+                AutofillHintsService autofillHintsService = mRequest.getAutofillHintsService();
+                if (autofillHintsService != null) {
+                    bundle.putBinder("AUTOFILL_HINTS_SERVICE", autofillHintsService.getBinder());
+                }
+            }
         }
         mRequest.fillViewStructure(structure);
         if (AutofillManagerWrapper.isLoggable()) {
@@ -380,10 +420,11 @@ public class AutofillProvider {
      * @param y the boundary of focus field.
      * @param width the boundary of focus field.
      * @param height the boundary of focus field.
+     * @param hasServerPrediction whether the server prediction arrived.
      */
     @CalledByNative
-    public void startAutofillSession(
-            FormData formData, int focus, float x, float y, float width, float height) {
+    public void startAutofillSession(FormData formData, int focus, float x, float y, float width,
+            float height, boolean hasServerPrediction) {
         // Check focusField inside short value?
         // Autofill Manager might have session that wasn't started by AutofillProvider,
         // we just always cancel existing session here.
@@ -394,7 +435,8 @@ public class AutofillProvider {
         Rect absBound = transformToWindowBounds(new RectF(x, y, x + width, y + height));
         if (mRequest != null) notifyViewExitBeforeDestroyRequest();
         transformFormFieldToContainViewCoordinates(formData);
-        mRequest = new AutofillRequest(formData, new FocusField((short) focus, absBound));
+        mRequest = new AutofillRequest(
+                formData, new FocusField((short) focus, absBound), hasServerPrediction);
         int virtualId = mRequest.getVirtualId((short) focus);
         notifyVirtualViewEntered(mContainerView, virtualId, absBound);
         mAutofillUMA.onSessionStarted(mAutofillManager.isDisabled());
@@ -713,6 +755,7 @@ public class AutofillProvider {
 
     @CalledByNative
     private void onQueryDone(boolean success) {
+        mRequest.onQueryDone(success);
         mAutofillManager.onQueryDone(success);
     }
 
diff --git a/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java b/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
index 4e01a399c98f3..0ab8cdfeec36e 100644
--- a/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
+++ b/components/autofill/android/provider/java/src/org/chromium/components/autofill/FormFieldData.java
@@ -5,6 +5,7 @@
 package org.chromium.components.autofill;
 
 import android.graphics.RectF;
+import android.view.autofill.AutofillId;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
@@ -67,6 +68,7 @@ public class FormFieldData {
     // after the object instantiated.
     private String mServerType;
     private String mComputedType;
+    private AutofillId mAutofillId;
 
     private FormFieldData(String name, String label, String value, String autocompleteAttr,
             boolean shouldAutocomplete, String placeholder, String type, String id,
@@ -172,6 +174,14 @@ public class FormFieldData {
         mAutofilled = autofilled;
     }
 
+    public void setAutofillId(AutofillId id) {
+        mAutofillId = id;
+    }
+
+    public AutofillId getAutofillId() {
+        return mAutofillId;
+    }
+
     @CalledByNative
     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
     public static FormFieldData createFormFieldData(String name, String label, String value,
diff --git a/components/autofill/android/provider/test_support/BUILD.gn b/components/autofill/android/provider/test_support/BUILD.gn
index a3c980458901e..74b3f5fcdc2f4 100644
--- a/components/autofill/android/provider/test_support/BUILD.gn
+++ b/components/autofill/android/provider/test_support/BUILD.gn
@@ -10,11 +10,14 @@ testonly = true
 android_library("component_autofill_provider_java_test_support") {
   annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
   sources = [
+    "java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java",
     "java/src/org/chromium/components/autofill/AutofillProviderTestHelper.java",
   ]
   deps = [
     "//base:base_java",
+    "//base:base_java_test_support",
     "//base:jni_java",
+    "//components/autofill/android/provider:autofill_aidl",
     "//components/autofill/android/provider:java",
     "//content/public/android:content_java",
     "//third_party/android_deps:androidx_annotation_annotation_java",
diff --git a/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java b/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java
new file mode 100644
index 0000000000000..742e98d7471b2
--- /dev/null
+++ b/components/autofill/android/provider/test_support/java/src/org/chromium/components/autofill/AutofillHintsServiceTestHelper.java
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.os.IBinder;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.components.autofill_public.IAutofillHintsService;
+import org.chromium.components.autofill_public.IViewTypeCallback;
+import org.chromium.components.autofill_public.ViewType;
+
+import java.util.List;
+
+/**
+ * This class implements and registers IViewTypeCallback for testing.
+ */
+public class AutofillHintsServiceTestHelper {
+    public void registerViewTypeService(IBinder binder) throws Exception {
+        IAutofillHintsService.Stub.asInterface(binder).registerViewTypeCallback(getBinder());
+    }
+
+    private IViewTypeCallback.Stub mBinder = new IViewTypeCallback.Stub() {
+        @Override
+        public void onViewTypeAvailable(List<ViewType> viewTypeList) {
+            mViewTypeList = viewTypeList;
+            mCallbackHelper.notifyCalled();
+        }
+
+        @Override
+        public void onQueryFailed() {
+            mQueryFailed = true;
+            mCallbackHelper.notifyCalled();
+        }
+    };
+
+    private List<ViewType> mViewTypeList;
+    private boolean mQueryFailed;
+    private CallbackHelper mCallbackHelper = new CallbackHelper();
+
+    public IViewTypeCallback getBinder() {
+        return mBinder;
+    }
+
+    public List<ViewType> getViewTypes() {
+        return mViewTypeList;
+    }
+
+    public boolean isQueryFailed() {
+        return mQueryFailed;
+    }
+
+    public void waitForCallbackInvoked() throws Exception {
+        mCallbackHelper.waitForCallback(0);
+    }
+}